package com.dzl.util.wx;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.dzl.config.ApplicationConfiguration;
import com.dzl.util.*;
import com.dzl.util.wx.pojo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.protocol.HTTP;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import static com.dzl.util.wx.constant.WxConstant.*;

/**
 * 功能描述：
 * @Author: lishunxing
 * @Date: 2020/11/24 19:04
 */
@Slf4j
public class WxUtils {


    /**
     * 获取微信网页授权登录url 通过此方法获取用户code
     * @param url 用户同意后回调接口
     * @return
     * @throws UnsupportedEncodingException
     * @author lishunxing
     */
    public static String getWeixinAuthorizeUrl(String url) throws UnsupportedEncodingException {
        String encode = URLEncoder.encode(url, "UTF-8");
        url = AUTHORIZE_URL.replace("URL", encode).replace("APPID", WxConfig.WX_APP_ID);
        return url;
    }


    /**
     * 通过code获取礼赠公众号用户信息
     * @author lishunxing
     */
    public static SNSUserInfo getUserInfo(String code) {
        JSONObject data = getAccessTokenAndOpenId(code, WxConfig.WX_APP_ID, WxConfig.WX_APP_SECRET);
        System.out.println(data.toJSONString());
        if (null != data) {
            return getUserInfo(data.getString("access_token"), data.getString("openid"));
        }
        log.error("用户授权获取用户信息失败！data : " + data.toJSONString());
        return null;
    }


    /**
     * 通过code获取公众号用户信息
     * @author lishunxing
     */
    public static SNSUserInfo getUserInfo(String code, String appId, String secret) {
        JSONObject data = getAccessTokenAndOpenId(code, appId, secret);
        System.out.println(data.toJSONString());
        if (null != data) {
            return getUserInfo(data.getString("access_token"), data.getString("openid"));
        }
        log.error("用户授权获取用户信息失败！data : " + data.toJSONString());
        return null;
    }

    /**
     * 获取网页授权微信用户信息
     * @author lishunxing
     */
    public static SNSUserInfo getUserInfo(String accessToken, String openId) {
        String res = "";
        try {
            // 通过code换取的是一个特殊的网页授权access_token,与基础支持中的access_token（该access_token用于调用其他接口）不同。
            String url = SNS_USERINFO_URL.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId);
            res = HttpUtil.sendGet(url, "UTF-8");
            System.out.println(res);
            return JSONObject.parseObject(res, SNSUserInfo.class);
        } catch (Exception e) {
            log.error("用户授权获取用户信息失败！res : " + res, e);
        }
        return null;
    }


    /**
     * 获取openId和access_token
     * @param appId  appid
     * @param code   用户code
     * @param secret 密钥
     * @author lishunxing
     */
    public static JSONObject getAccessTokenAndOpenId(String code, String appId, String secret) {
        String res = "";
        try {
            String url = OAUTH_URL.replace("APPID", appId).replace("SECRET", secret).replace("CODE", code);
            res = HttpUtil.sendGet(url, "UTF-8");
            return JSONObject.parseObject(res);
        } catch (Exception e) {
            log.error("获取OPENID失败！res : " + res, e);
        }
        return null;
    }

    /**
     * 获取小程序用户openId
     * @author lishunxing
     * @params 小程序APPID 密钥 code
     */
    public static XcxAuthInfo getXcxOpenId(String appId, String secret, String code) {
        String res = "";
        try {
            String url = XCX_OAUTH_URL.replace("APPID", appId).replace("SECRET", secret).replace("JSCODE", code);
            res = HttpUtil.sendGet(url, "UTF-8");
            return JSONObject.parseObject(res, XcxAuthInfo.class);
        } catch (Exception e) {
            log.error("获取小程序OPENID失败！ res : " + res, e);
        }
        return null;
    }


    /**
     * 获取公众号AccessToken
     * @author lishunxing
     */
    public static String getAccessToken(String appId, String secret) {
        String key = "access_token" + appId;
        try {
            String s = String.valueOf(RedisUtil.get(key));
            if ("null".equals(s)) {
                String url = ACCESS_TOKEN_URL.replace("APPID", appId).replace("SECRET", secret);
                String res = HttpUtil.sendGet(url, "UTF-8");
                s = JSONObject.parseObject(res).getString("access_token");
                RedisUtil.set(key, s, 7200);
            }
            return s;
        } catch (Exception e) {
            log.error("获取AccessToken失败！", e);
        }
        return null;
    }

    /**
     * 获取小程序码（圆形）
     * @param scene     二维码设置携带参数
     * @param page      小程序跳转路径
     * @param appId
     * @param appSecret
     * @return
     * @throws Exception
     * @author 杨浩
     * @Date 2020/12/11 09:22
     */
    public static InputStream getQRCode(String scene, String page, String appId, String appSecret) throws Exception {

        String token = getAccessToken(appId, appSecret);   // 得到token

        Map<String, Object> params = new HashMap<>();
        params.put("scene", scene);  //参数 Q21000087
        params.put("page", page); //位置 "pages/quickExchange/index"
        params.put("width", 300);
        log.info("获取小程序码=========================> scene:"+scene+",page:"+page+",appId:"+appId+",appSecret:"+appSecret);
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        String url = GET_WX_XXC_CODE_UNLIMIT.replace("TOKEN", token);
        HttpPost httpPost = new HttpPost(url);  // 接口
        httpPost.addHeader(HTTP.CONTENT_TYPE, "application/json");
        String body = JSON.toJSONString(params);           //必须是json模式的 post
        StringEntity entity;
        entity = new StringEntity(body);
        entity.setContentType("image/png");

        httpPost.setEntity(entity);
        HttpResponse response;

        response = httpClient.execute(httpPost);
        InputStream inputStream = response.getEntity().getContent();

        return inputStream;
    }

    /**
     * 小程序获取普通二维码（正方形）
     * @param path      扫码进入的小程序页面路径，最大长度 128 字节，不能为空；对于小游戏，可以只传入 query 部分，来实现传参效果，如：传入 "?foo=bar"，即可在 wx.getLaunchOptionsSync 接口中的 query 参数获取到 {foo:"bar"}。
     * @param appId
     * @param appSecret
     * @author 杨浩
     * @Date 2021/01/04 14:04
     */
    public static InputStream getQRCode(String path, String appId, String appSecret) throws Exception {
        String token = getAccessToken(appId, appSecret);   // 得到token
        Map<String, Object> params = new HashMap<>();
        //String scene = "id=" + blindActivityId + ",code=" + invitationCode;
        //params.put("scene", scene);  //参数
        params.put("path", path);
        params.put("width", 300);
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        String url = CREATE_WX_XXC_QRCODET.replace("TOKEN", token);
//        HttpUtil.sendPostUrl(url, params, charset)
        HttpPost httpPost = new HttpPost(url);  // 接口
        httpPost.addHeader(HTTP.CONTENT_TYPE, "application/json");
        String body = JSON.toJSONString(params);           //必须是json模式的 post
        StringEntity entity;
        entity = new StringEntity(body);
        entity.setContentType("image/png");
        httpPost.setEntity(entity);
        HttpResponse response;
        response = httpClient.execute(httpPost);
        InputStream inputStream = response.getEntity().getContent();
        return inputStream;
    }


    public static void main(String[] args) throws Exception {
        /*String imageName = "gQHm8jwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyU0lGQzlTMS1jMEQxMDAwMDAwN0YAAgS_he1fAwQAAAAA";
        String s = URLEncoder.encode(imageName, "UTF-8");
        JSONObject sS = createQrCode("aa","wxef4690e7b6c5931a","9b0075ed99f43cd71afe1dfe1be2b321");*/
        //InputStream s = getQRCode("pages/blindbox/index?boxId=1,userId=2,code=12xx3", WxConfig.WX_XCX_APPID, WxConfig.WX_XCX_SECRET);
        //System.out.println(s);
    }

    private static void generateQRCodeImage(String qrcodeUrl, int width, int height, String filePath) throws WriterException, IOException {
        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        BitMatrix bitMatrix = qrCodeWriter.encode(qrcodeUrl, BarcodeFormat.QR_CODE, width, height);
        Path path = FileSystems.getDefault().getPath(filePath);
        MatrixToImageWriter.writeToPath(bitMatrix, "PNG", path);
    }

    /******
     * 创建普通二维码（正方形）
     * @param qrcodeUrl 二维码链接
     * @return
     */
    public static String getQRCode(String qrcodeUrl) {
        String ctxPath = "D://file";
        if (FileUtil.isOSLinux()) {
            ctxPath = File.separator + "opt" + File.separator + "static" + File.separator + "libei";
        }
        String fileName = "twoCode.png";
        String bizPath = "files";
        String qrCode = "files";
        try {
            String nowday = new SimpleDateFormat("yyyyMMdd").format(new Date());
            //String ppath =ctxPath + File.separator + bizPath + File.separator + nowday;
            File file = new File(ctxPath + File.separator + bizPath + File.separator + nowday);
            if (!file.exists()) {
                file.mkdirs();// 创建文件根目录
            }
            String savePath = file.getPath() + File.separator + fileName;
            qrCode = bizPath + File.separator + nowday + File.separator + fileName;
            if (savePath.contains("\\")) {
                savePath = savePath.replace("\\", "/");
            }
            if (qrCode.contains("\\")) {
                qrCode = qrCode.replace("\\", "/");
            }
            generateQRCodeImage(qrcodeUrl, 300, 300, savePath);
            return ctxPath + File.separator + qrCode;
        } catch (WriterException e) {
            System.out.println("Could not generate QR Code, WriterException :: " + e.getMessage());
        } catch (IOException e) {
            System.out.println("Could not generate QR Code, IOException :: " + e.getMessage());
        }
        return qrCode;
    }


    /**
     * 公众号推送模板消息给用户
     * @param openId     用户公众号下的openId
     * @param templateId 信息ID
     * @param data       消息内容
     * @return boolean
     * @date 2020/12/22 14:33
     * @author lishunxing
     */
    public static WxResponse sendTemplateMessage(String openId, String templateId, Object data) {
        String url = TEMPLATE_MESSAGE.replace("ACCESS_TOKEN", Objects.requireNonNull(getAccessToken(WxConfig.WX_APP_ID, WxConfig.WX_APP_SECRET)));
        TemplateMessage templateMessage = new TemplateMessage();
        templateMessage.setTouser(openId);
        templateMessage.setTemplate_id(templateId);
        MiniProgram miniProgram = new MiniProgram();
        miniProgram.setAppid(WxConfig.WX_XCX_APPID);
        miniProgram.setPagepath(null);
        templateMessage.setMiniprogram(miniProgram);
        templateMessage.setData(data);

        String res = HttpUtil.sendPostUrl(url, JSON.toJSONString(templateMessage), "UTF-8");
        return JSON.parseObject(res, WxResponse.class);
    }

    /**
     * 公众号发送代付成功信息通知给购买用户
     * @param openId    需要接受消息的用户公众号ID
     * @param orderNo   订单号
     * @param agentName 代付人昵称
     * @param price     代付金额
     * @return boolean 是否成功
     * @date 2020/12/22 19:21
     * @author lishunxing
     */
    public static boolean sendAgentPayTemplateMessage(String openId, String orderNo, String agentName, String price) {
        Map params = new HashMap(7);
        Map titleContent = generatorContent("订单代付成功通知", PUBLIC_LOGIN_TYPE);
        Map noContent = generatorContent(orderNo, PUBLIC_LOGIN_TYPE);
        Map NameContent = generatorContent(agentName, PUBLIC_LOGIN_TYPE);
        Map priceContent = generatorContent(price, PUBLIC_LOGIN_TYPE);
        Map dateContent = generatorContent(DateUtil.getNow(), PUBLIC_LOGIN_TYPE);
        Map msgContent = generatorContent("无", PUBLIC_LOGIN_TYPE);
        Map remarkContent = generatorContent("点击详情查看订单详细信息，有疑问可咨询在线客服。", PUBLIC_LOGIN_TYPE);
        params.put("first", titleContent);
        params.put("keyword1", noContent);
        params.put("keyword2", NameContent);
        params.put("keyword3", priceContent);
        params.put("keyword4", dateContent);
        params.put("keyword5", msgContent);
        params.put("remark", remarkContent);
        WxResponse wxResponse = sendTemplateMessage(openId, WxConfig.AGENT_PAY_TEMPLATE_ID, params);
        if (!wxResponse.getErrcode().equals("0")) {
            log.error("微信代付成功模板消息推送失败, 原因：" + wxResponse.getErrmsg());
            return false;
        }
        return true;
    }

    /**
     * 生成公众号模板消息内容体
     * @param value 内容
     * @param type  1小程序 2公众号
     * @return java.util.Map
     * @date 2020/12/22 19:33
     * @author lishunxing
     */
    private static Map generatorContent(String value, Integer type) {
        Map content = new HashMap(type);
        content.put("value", value);
        if (type.equals(PUBLIC_LOGIN_TYPE)) {
            content.put("color", "#173177");
        }
        return content;
    }

    /**
     * 小程序微信发送模板消息
     * @param appId      小程序APPID
     * @param secret     秘钥
     * @param openId     接受者openId
     * @param templateId 模板ID
     * @param page       点击后跳转页面路劲
     * @param map        模板参数
     * @return
     * @date 2021/01/07 9:54
     * @author lishunxing
     */
    public static WxResponse sendXcxTemplateMessage(String appId, String secret, String openId, String templateId, String page,
                                                    Map map) {
        String url = XCX_TEMPLATE_MESSAGE.replace("TOKEN", getAccessToken(appId, secret));
        XcxTemplateMessage sendTemplateMessage = new XcxTemplateMessage();
        sendTemplateMessage.setTouser(openId);
        sendTemplateMessage.setTemplate_id(templateId);
        sendTemplateMessage.setPage(page);
        sendTemplateMessage.setData(map);
        String isProduct = ApplicationConfiguration.getInstance().getIsProduct();
        if (isProduct == null || "0".equals(isProduct)) {
            //体验版小程序
            sendTemplateMessage.setMiniprogram_state("trial");//测试服使用
        }
        String json = JSONObject.toJSONString(sendTemplateMessage);
        WxResponse response;
        try {
            String ret = HttpUtil.sendPostUrl(url, json, "utf-8");
            response = JSON.parseObject(ret, WxResponse.class);
        } catch (Exception e) {
            log.error("模板消息发送失败 : " + json);
            response = new WxResponse();
            response.setErrcode("-1");
            response.setErrmsg(e.getMessage());
        }
        return response;
    }
}
